import os
import json
from flask import Flask, url_for, redirect, render_template, request, abort, send_from_directory
from flask_sqlalchemy import SQLAlchemy
from flask_security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin, current_user
from flask_security.utils import encrypt_password
from flask_admin.contrib import sqla
from flask_admin import helpers as admin_helpers
from flask_admin import Admin
from wtforms import PasswordField
from flask_admin.contrib.fileadmin import FileAdmin
import os.path as op
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager, Server
from flask_admin import BaseView, expose

app = Flask(__name__)
app.config.from_pyfile('config.py')
db = SQLAlchemy()
manager = Manager(app)
Migrate(app, db)
manager.add_command('db', MigrateCommand)
db.init_app(app)
manager.add_command("runserver", Server(host=app.config['HOST'], port=app.config['PORT']))
roles_users = db.Table(
    'roles_users',
    db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
    db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
)


class Role(db.Model, RoleMixin):
    __tablename__ = 'role'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), unique=True)
    description = db.Column(db.String(255))

    def __str__(self):
        return self.name


class User(db.Model, UserMixin):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    email = db.Column(db.String(255), unique=True, nullable=False)
    password = db.Column(db.String(255), nullable=False)
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

    def __str__(self):
        return self.email


class ProductType(db.Model):
    __tablename__ = 'product_type'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), unique=True)
    images_url = db.Column(db.String(255), nullable=False)
    nav_display = db.Column(db.Integer(), default=0)
    index_display = db.Column(db.Integer(), default=0)
    description = db.Column(db.String(255))
    weight = db.Column(db.Integer())

    def __str__(self):
        return self.name


class Product(db.Model):
    __tablename__ = 'product'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), unique=True, nullable=False)
    title = db.Column(db.String(255), nullable=False)
    images_url = db.Column(db.String(255), nullable=False)
    weight = db.Column(db.Integer())
    product_type_id = db.Column(db.Integer, db.ForeignKey('product_type.id'))
    product_type = db.relationship("ProductType", backref="product")

    def __str__(self):
        return self.name


class ProductParm(db.Model):
    __tablename__ = 'product_parm'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), nullable=False)
    small_images_url = db.Column(db.String(255), nullable=False)
    list_images_url = db.Column(db.String(255), nullable=False)
    images_url = db.Column(db.String(255), nullable=False)
    title = db.Column(db.String(255), nullable=False)
    product_model = db.Column(db.String(255), nullable=False)
    description = db.Column(db.Text())
    customize_description = db.Column(db.Text())
    index_display = db.Column(db.Integer(), default=0)
    weight = db.Column(db.Integer())
    product_id = db.Column(db.Integer, db.ForeignKey('product.id'))
    product = db.relationship("Product", backref="product_parm")

    def __str__(self):
        return self.name


class DownLoad(db.Model):
    __tablename__ = 'download'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), nullable=False)
    file_link = db.Column(db.String(255))
    description = db.Column(db.Text())
    product_parm_id = db.Column(db.Integer, db.ForeignKey('product_parm.id'))
    product_parm = db.relationship("ProductParm", backref="download")

    def __str__(self):
        return self.name


class FirstClass(db.Model):
    __tablename__ = 'first_class'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), unique=True)
    images_url = db.Column(db.String(255), nullable=False)

    def __str__(self):
        return self.name


class SecondClass(db.Model):
    __tablename__ = 'second_class'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), unique=True, nullable=False)
    customize_description = db.Column(db.Text())
    first_class_id = db.Column(db.Integer, db.ForeignKey('first_class.id'))
    first_class = db.relationship("FirstClass", backref="first_class")

    def __str__(self):
        return self.name


class Images(db.Model):
    __tablename__ = 'images'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), nullable=False)
    images_url = db.Column(db.String(255), nullable=False)
    type = db.Column(db.String(255), nullable=False)
    weight = db.Column(db.Integer())

    def __str__(self):
        return self.name


class IndustryApplication(db.Model):
    __tablename__ = 'industry_application'
    id = db.Column(db.Integer(), primary_key=True)
    title = db.Column(db.String(255), nullable=False)
    images_url = db.Column(db.String(255), nullable=False)
    description = db.Column(db.Text())
    url = db.Column(db.String(255))
    weight = db.Column(db.Integer())

    def __str__(self):
        return self.name


class TechnicalSkills(db.Model):
    __tablename__ = 'technical_skills'
    id = db.Column(db.Integer(), primary_key=True)
    title = db.Column(db.String(255), nullable=False)
    images_url = db.Column(db.String(255), nullable=False)
    hover_images_url = db.Column(db.String(255), nullable=False)
    url = db.Column(db.String(255))
    description = db.Column(db.Text())
    weight = db.Column(db.Integer())

    def __str__(self):
        return self.name


class Connect(db.Model):
    __tablename__ = 'connect'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255), nullable=False)
    phone = db.Column(db.String(255))
    email = db.Column(db.String(255))
    company = db.Column(db.String(255))
    type = db.Column(db.String(255))
    description = db.Column(db.Text())

    def __str__(self):
        return self.name


user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)


class MyModelView(sqla.ModelView):
    def is_accessible(self):
        if not current_user.is_active or not current_user.is_authenticated:
            return False

        if current_user.has_role('superuser'):
            return True
        return False

    def _handle_view(self, name, **kwargs):
        if not self.is_accessible():
            if current_user.is_authenticated:
                # permission denied
                abort(403)
            else:
                # login
                return redirect(url_for('security.login', next=request.url))

            # can_edit = True

    edit_modal = True
    create_modal = True
    can_export = True
    # can_view_details = True
    details_modal = True


class MyDefModelView(sqla.ModelView):
    edit_modal = True
    create_modal = True
    details_modal = True

    def is_accessible(self):
        if not current_user.is_active or not current_user.is_authenticated:
            return False

        return True

    def _handle_view(self, name, **kwargs):
        if not self.is_accessible():
            if current_user.is_authenticated:
                # permission denied
                abort(403)
            else:
                # login
                return redirect(url_for('security.login', next=request.url))

admin = Admin(
    app,
    '吉派流体控制技术',
    template_mode='bootstrap4',
)


class UserView(MyModelView):
    column_editable_list = ['name']
    column_searchable_list = column_editable_list
    column_exclude_list = ['password']
    column_details_exclude_list = column_exclude_list
    form_overrides = {
        "password": PasswordField
    }


class FileView(FileAdmin):
    def is_accessible(self):
        if not current_user.is_active or not current_user.is_authenticated:
            return False
        if current_user.has_role('superuser'):
            return True
        return False


class ImagesView(MyModelView):
    column_editable_list = []
    column_searchable_list = column_editable_list


class ProductTypeView(MyDefModelView):
    column_editable_list = ['name']
    column_searchable_list = column_editable_list


class ProductView(MyDefModelView):
    column_editable_list = ['name']
    column_searchable_list = column_editable_list


class ProductParmView(MyDefModelView):
    column_editable_list = ['name']
    column_searchable_list = column_editable_list


class FirstClassView(MyModelView):
    column_editable_list = ['name']
    column_searchable_list = column_editable_list


class SecondClassView(MyModelView):
    column_editable_list = ['name']
    column_searchable_list = column_editable_list


class IndustryApplicationView(MyModelView):
    column_editable_list = []
    column_searchable_list = column_editable_list


class TechnicalSkillsView(MyModelView):
    column_editable_list = []
    column_searchable_list = column_editable_list


class ConnectView(MyDefModelView):
    column_editable_list = []
    column_searchable_list = column_editable_list


class DownLoadView(MyDefModelView):
    column_editable_list = []
    column_searchable_list = column_editable_list


# Add model views


admin.add_view(MyModelView(Role, db.session, menu_icon_type='fa', menu_icon_value='fa-server', name="用户规则"))
admin.add_view(UserView(User, db.session, menu_icon_type='fa', menu_icon_value='fa-users', name="用户管理"))
admin.add_view(ImagesView(Images, db.session, menu_icon_type='fa', menu_icon_value='fa-image', name="图片管理"))
admin.add_view(IndustryApplicationView(IndustryApplication, db.session, menu_icon_type='fa', menu_icon_value='fa-cogs',
                                       name="行业应用"))
admin.add_view(TechnicalSkillsView(TechnicalSkills, db.session, menu_icon_type='fa', menu_icon_value='fa-cogs',
                                   name="技术能力"))
admin.add_view(ProductTypeView(ProductType, db.session, menu_icon_type='fa', menu_icon_value='fa-cubes  ',
                               name="产品类型"))
admin.add_view(ProductView(Product, db.session, menu_icon_type='fa', menu_icon_value='fa-cubes', name="产品"))
admin.add_view(ProductParmView(ProductParm, db.session, menu_icon_type='fa', menu_icon_value='fa-cubes',
                               name="产品参数"))
admin.add_view(DownLoadView(DownLoad, db.session, menu_icon_type='fa', menu_icon_value='fa-download',
                            name="相关资料"))
admin.add_view(FirstClassView(FirstClass, db.session, menu_icon_type='fa', menu_icon_value='fa-sitemap',
                              name="一级目录"))
admin.add_view(SecondClassView(SecondClass, db.session, menu_icon_type='fa', menu_icon_value='fa-sitemap',
                               name="二级目录"))
admin.add_view(ConnectView(Connect, db.session, menu_icon_type='fa', menu_icon_value='fa-connectdevelop',
                           name="联系记录"))
path = op.join(op.dirname(__file__), 'static')
admin.add_view(
    FileView(path, '/static/', name='静态文件', menu_icon_type='fa', menu_icon_value='fa-archive'))


def get_product_type_list():
    product_type = ProductType.query.order_by(ProductType.weight.desc()).filter_by(nav_display=1)
    product_type_list = []
    for i in product_type:
        product_type_dict = {'product_type': i.name, 'product_type_img': i.images_url,
                             'product_type_dec': i.description, 'product_type_id': i.id}
        product = Product.query.order_by(Product.weight.desc()).filter_by(product_type_id=i.id)
        product_list = []
        for k in product:
            product_dict = {
                'id': k.id,
                'name': k.name
            }
            product_list.append(product_dict)
        product_type_dict['product'] = product_list
        product_type_list.append(product_type_dict)
    return product_type_list


def get_product_list(product_type_id):
    product = Product.query.order_by(Product.weight.desc()).filter_by(product_type_id=product_type_id)
    product_list = []
    for i in product:
        product_dict = {'product_name': i.name, 'product_img': i.images_url, 'product_title': i.title,
                        'product_id': i.id}
        product_parm = ProductParm.query.order_by(ProductParm.weight.desc()).filter_by(product_id=i.id)
        product_parm_list = []
        for k in product_parm:
            product_parm_dict = {
                'id': k.id,
                'name': k.name,
                'list_images_url': k.list_images_url,
                'title': k.title,
            }
            product_parm_list.append(product_parm_dict)

        product_dict['product_parm_list'] = product_parm_list[-3:]
        product_list.append(product_dict)
    return product_list


def get_first_class_list(second_class_id):
    second_class = SecondClass.query.filter_by(id=second_class_id)[0]
    first_class = FirstClass.query.filter_by(id=second_class.first_class_id)
    first_class_list = []
    for i in first_class:
        first_class_dict = {'first_class': i.name, 'first_class_img': i.images_url}
        second_class_in = SecondClass.query.filter_by(first_class_id=i.id)
        second_class_list = []
        for k in second_class_in:
            second_class_dict = {
                'id': k.id,
                'name': k.name
            }
            second_class_list.append(second_class_dict)
        first_class_dict['second_class_list'] = second_class_list
        first_class_list.append(first_class_dict)
    return first_class_list


def get_index_product_list(name):
    pro_type = ProductType.query.filter_by(name=name)
    product = Product.query.filter_by(product_type_id=pro_type[0].id)
    id_list = [i.id for i in product]
    index_product_list = ProductParm.query.filter(ProductParm.product_id.in_(id_list))
    return index_product_list


def get_index_first(name):
    cls = FirstClass.query.filter_by(name=name)
    sc = SecondClass.query.filter_by(first_class_id=cls[0].id)
    return sc


def get_down_load_list(down_load):
    down_load_list = []
    for i in down_load:
        file_type = i.file_link.split('.')[-1]
        down_load_dict = {
            'name': i.name,
            'link': i.file_link,
            'file_type': file_type
        }
        down_load_list.append(down_load_dict)
    return down_load_list


@security.context_processor
def security_context_processor():
    return dict(
        admin_base_template=admin.base_template,
        admin_view=admin.index_view,
        h=admin_helpers,
        get_url=url_for
    )


@app.route('/upload', methods=["POST"])
def upload_file():
    if request.method == 'POST':
        this_file = request.files.get("images", '')
        root_path = op.join(op.dirname(__file__), 'static')
        static_path = "images/upload_img/"
        img_name = this_file.filename
        file_path = static_path + img_name
        abs_file_path = os.path.join(root_path, file_path)
        this_file.save(abs_file_path)
        rel_path = "/static/images/upload_img/" + img_name
        return {"status": "success", "file_path": rel_path}
    else:
        return {"status": "Fail", "date": "request must be post"}


@app.route('/', methods=["GET"])
def index():
    banners = Images.query.order_by(Images.weight.desc()).filter_by(type='banner')
    about_big = Images.query.order_by(Images.weight.desc()).filter_by(type='about_big')
    about_small = Images.query.order_by(Images.weight.desc()).filter_by(type='about_small')
    industry_application = IndustryApplication.query.order_by(IndustryApplication.weight.desc()) \
        .all()
    technical_skills = TechnicalSkills.query.order_by(TechnicalSkills.weight.desc()) \
        .all()
    industry_application_nav_one = get_index_first('行业应用')
    industry_application_nav_two = get_index_first('技术能力')
    industry_application_nav_three = get_index_first('关于吉派')
    industry_application_nav_four = get_index_first('联系我们')
    product_type_list = get_product_type_list()

    product_type = ProductType.query.order_by(ProductType.weight.desc()).filter_by(index_display='1')
    product_type_index_list = []
    for i in product_type:
        index_product_list = get_index_product_list(i.name)
        product_type_index_dict = {
            'name': i.name,
            'description': i.description,
            "index_product_list": index_product_list

        }
        product_type_index_list.append(product_type_index_dict)
    return render_template('index.html', **locals())


@app.route('/index_connect', methods=["POST"])
def index_connect():
    if request.method == 'POST':
        name = request.form.get('name', '')
        phone = request.form.get('phone', '')
        description = request.form.get('description', '')
        connect = Connect(name=name, phone=phone, description=description)
        db.session.add(connect)
        db.session.commit()
        return {"status": "success"}
    else:
        return {"status": "Fail", "date": "request must be post"}


@app.route('/connect', methods=["POST"])
def connect():
    if request.method == 'POST':
        name = request.form.get('name', '')
        phone = request.form.get('phone', '')
        email = request.form.get('email', '')
        company = request.form.get('company', '')
        type = request.form.get('type', '')
        description = request.form.get('description', '')
        connect = Connect(name=name, phone=phone, description=description,
                          email=email, company=company, type=type)
        db.session.add(connect)
        db.session.commit()
        return {"status": "success"}
    else:
        return {"status": "Fail", "date": "request must be post"}


@app.route('/product_type/<product_type_id>', methods=["GET"])
def product_type_func(product_type_id):
    if request.method == 'GET':
        industry_application_nav_one = get_index_first('行业应用')
        industry_application_nav_two = get_index_first('技术能力')
        industry_application_nav_three = get_index_first('关于吉派')
        industry_application_nav_four = get_index_first('联系我们')
        product_type_list = get_product_type_list()
        product_type = ProductType.query.filter_by(id=product_type_id)[0]
        product = Product.query.filter_by(product_type_id=product_type_id)
        product_list = get_product_list(product_type_id)
        return render_template('product_first_list.html', **locals())
    else:
        return render_template('404.html', **locals())


@app.route('/product_list/<product_id>', methods=["GET"])
def product_list_func(product_id):
    if request.method == 'GET':
        industry_application_nav_one = get_index_first('行业应用')
        industry_application_nav_two = get_index_first('技术能力')
        industry_application_nav_three = get_index_first('关于吉派')
        industry_application_nav_four = get_index_first('联系我们')
        product_type_list = get_product_type_list()

        product = Product.query.filter_by(id=product_id)
        product_type = ProductType.query.filter_by(id=product[0].product_type_id)
        product_parm = ProductParm.query.filter_by(product_id=product_id)
        return render_template('product_second_list.html', **locals())
    else:
        return render_template('404.html', **locals())


@app.route('/product_parm/<product_parm_id>', methods=["GET"])
def product_parm_func(product_parm_id):
    if request.method == 'GET':
        industry_application_nav_one = get_index_first('行业应用')
        industry_application_nav_two = get_index_first('技术能力')
        industry_application_nav_three = get_index_first('关于吉派')
        industry_application_nav_four = get_index_first('联系我们')
        product_type_list = get_product_type_list()
        product_parm = ProductParm.query.filter_by(id=product_parm_id)[0]
        product = Product.query.filter_by(id=product_parm.product_id)
        down_load = DownLoad.query.filter_by(product_parm_id=product_parm_id)
        return render_template('product.html', **locals())
    else:
        return render_template('404.html', **locals())


@app.route('/second_class/<second_class_id>', methods=["GET"])
def second_class_func(second_class_id):
    if request.method == 'GET':
        industry_application_nav_one = get_index_first('行业应用')
        industry_application_nav_two = get_index_first('技术能力')
        industry_application_nav_three = get_index_first('关于吉派')
        industry_application_nav_four = get_index_first('联系我们')
        product_type_list = get_product_type_list()
        second_class = SecondClass.query.filter_by(id=second_class_id)[0]
        first_class = FirstClass.query.filter_by(id=second_class.first_class_id)
        first_class_list = get_first_class_list(second_class_id)
        if second_class.name == '联系方式':
            return render_template('contact.html', **locals())
        elif second_class.name == '在线咨询':
            return render_template('contact_ol.html', **locals())
        else:
            return render_template('second.html', **locals())
    else:
        return render_template('404.html', **locals())


@app.route('/search/', methods=["GET"])
def search_func():
    if request.method == 'GET':
        industry_application_nav_one = get_index_first('行业应用')
        industry_application_nav_two = get_index_first('技术能力')
        industry_application_nav_three = get_index_first('关于吉派')
        industry_application_nav_four = get_index_first('联系我们')
        product_type_list = get_product_type_list()
        search_key = request.args.get('key', '')
        product_pram = ProductParm.query.filter(ProductParm.name.like("%" + search_key + "%"))
        product_pram_len = product_pram.count()
        down_load = DownLoad.query.filter(DownLoad.name.like("%" + search_key + "%"))
        down_load_list = get_down_load_list(down_load)
        down_load_len = down_load.count()
        return render_template('search.html', **locals())


if __name__ == '__main__':
    # build_sample_db()
    manager.run()
